package com.ac.core.utility;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.MatchResult;
import org.apache.oro.text.regex.PatternCompiler;
import org.apache.oro.text.regex.PatternMatcherInput;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;

public class RegexParser {
    public static class MatchedMap extends Mapx
    {

        public String get(String key)
        {
            return (String)super.get(key);
        }

        public String getMatchedString()
        {
            return MatchedString;
        }

        private String MatchedString;


        public MatchedMap()
        {
        }
    }

    public RegexParser(String regexTemplate)
    {
        fullMatch = false;
        this.regexTemplate = regexTemplate;
        compileItem();
    }

    public RegexParser(String regexTemplate, boolean fullMatch)
    {
        this.fullMatch = false;
        this.fullMatch = fullMatch;
        this.regexTemplate = regexTemplate;
        compileItem();
    }

    private void compileItem()
    {
        regexTemplate = regexTemplate.replaceAll("\\r\\n", "\n");
        String lines[] = regexTemplate.split("\\n");
        StringBuffer sb = new StringBuffer();
        boolean firstFlag = true;
        for(int i = 0; i < lines.length; i++)
        {
            String line = lines[i].trim();
            if(!StringUtil.isEmpty(line))
            {
                if(!firstFlag)
                    sb.append("\\s*");
                firstFlag = false;
                sb.append(encodeRegex(line));
            }
        }

        regexTemplate = sb.toString();
        Matcher matcher = PField.matcher(regexTemplate);
        int lastIndex = 0;
        ArrayList arr = new ArrayList();
        sb = new StringBuffer();
        for(; matcher.find(lastIndex); lastIndex = matcher.end())
        {
            sb.append(regexTemplate.substring(lastIndex, matcher.start()));
            String type = matcher.group(1);
            String name = matcher.group(2);
            if(!StringUtil.isEmpty(name))
                sb.append("(");
            if(type.equalsIgnoreCase("A"))
                sb.append("[^\000]*?");
            else
            if(type.equalsIgnoreCase("D"))
                sb.append("\\d*?");
            else
            if(type.equalsIgnoreCase("W"))
                sb.append("\\w*?");
            else
            if(type.equalsIgnoreCase("-D"))
                sb.append("\\D*?");
            else
            if(type.equalsIgnoreCase("-W"))
                sb.append("\\W*?");
            if(!StringUtil.isEmpty(name))
            {
                sb.append(")");
                arr.add(name.substring(1));
            }
        }

        sb.append(regexTemplate.substring(lastIndex));
        regexTemplate = sb.toString();
        matcher = PSpecial.matcher(regexTemplate);
        sb = new StringBuffer();
        for(lastIndex = 0; matcher.find(lastIndex); lastIndex = matcher.end())
        {
            sb.append(regexTemplate.substring(lastIndex, matcher.start()));
            String pattern = matcher.group(1);
            String name = matcher.group(2);
            if(!StringUtil.isEmpty(name))
                sb.append("(");
            sb.append(pattern);
            if(!StringUtil.isEmpty(name))
            {
                sb.append(")");
                arr.add(name.substring(2));
            }
        }

        sb.append(regexTemplate.substring(lastIndex));
        itemFields = new String[arr.size()];
        for(int i = 0; i < arr.size(); i++)
            itemFields[i] = (String)arr.get(i);

        regexTemplate = sb.toString();
        regexTemplate = StringUtil.replaceEx(regexTemplate, "$", "\\$");
        regexTemplate = StringUtil.replaceEx(regexTemplate, "{", "\\{");
        regexTemplate = StringUtil.replaceEx(regexTemplate, "}", "\\}");
        if(fullMatch)
            regexTemplate = "^" + regexTemplate + "$";
        PatternCompiler compiler = new Perl5Compiler();
        try
        {
            this.pattern = compiler.compile(regexTemplate, 9);
        }
        catch(MalformedPatternException e)
        {
            e.printStackTrace();
        }
    }

    public static String encodeRegex(String str)
    {
        str = str.trim();
        str = StringUtil.replaceEx(str, "\"", "\\\"");
        str = StringUtil.replaceEx(str, "'", "\\'");
        str = StringUtil.replaceEx(str, "?", "\\?");
        str = StringUtil.replaceEx(str, "^", "\\^");
        str = StringUtil.replaceEx(str, "&", "\\&");
        str = StringUtil.replaceEx(str, "-", "\\-");
        str = StringUtil.replaceEx(str, "*", "\\*");
        str = StringUtil.replaceEx(str, ".", "\\.");
        str = StringUtil.replaceEx(str, "(", "\\(");
        str = StringUtil.replaceEx(str, ")", "\\)");
        str = StringUtil.replaceEx(str, "[", "\\[");
        str = StringUtil.replaceEx(str, "]", "\\]");
        str = StringUtil.replaceEx(str, "=", "\\=");
        str = StringUtil.replaceEx(str, "!", "\\!");
        str = StringUtil.replaceEx(str, "\t", "\\t");
        str = StringUtil.replaceEx(str, "\r", "\\r");
        return str;
    }

    public boolean matches(String content)
    {
        content = content.replaceAll("\\r\\n", "\n");
        PatternMatcherInput input = new PatternMatcherInput(content);
        Perl5Matcher matcher = new Perl5Matcher();
        return matcher.contains(input, pattern);
    }

    public String replace(String content, String replacement)
    {
        content = content.replaceAll("\\r\\n", "\n");
        PatternMatcherInput input = new PatternMatcherInput(content);
        Perl5Matcher matcher = new Perl5Matcher();
        StringBuffer sb = new StringBuffer();
        int lastIndex;
        for(lastIndex = 0; matcher.contains(input, pattern); lastIndex = input.getCurrentOffset())
        {
            MatchResult result = matcher.getMatch();
            sb.append(content.substring(lastIndex, input.getCurrentOffset() - result.length()));
            sb.append(replacement);
        }

        sb.append(content.substring(lastIndex, content.length()));
        return sb.toString();
    }

    public MatchedMap[] getMatchedMaps(String content)
    {
        content = content.replaceAll("\\r\\n", "\n");
        ArrayList arr = new ArrayList();
        PatternMatcherInput input = new PatternMatcherInput(content);
        MatchedMap map;
        for(Perl5Matcher matcher = new Perl5Matcher(); matcher.contains(input, pattern); arr.add(map))
        {
            MatchResult result = matcher.getMatch();
            map = new MatchedMap();
            for(int i = 0; i < itemFields.length; i++)
                map.put(itemFields[i], result.group(i + 1));

            map.MatchedString = result.group(0);
        }

        MatchedMap maps[] = new MatchedMap[arr.size()];
        for(int i = 0; i < arr.size(); i++)
            maps[i] = (MatchedMap)arr.get(i);

        return maps;
    }

    public String getRegexTemplate()
    {
        return regexTemplate;
    }

    public String[] getKeys()
    {
        ArrayList arr = new ArrayList();
        for(int i = 0; i < itemFields.length; i++)
            arr.add(itemFields[i]);

        String r[] = new String[arr.size()];
        for(int i = 0; i < r.length; i++)
            r[i] = (String)arr.get(i);

        return r;
    }

    private String regexTemplate;
    private String itemFields[];
    private org.apache.oro.text.regex.Pattern pattern;
    private boolean fullMatch;
    public static final Pattern PField = Pattern.compile("\\$\\{(\\w+?)(\\:[^\\}]+?)?\\}");
    public static final Pattern PSpecial = Pattern.compile("\\$\\{\\{(.+?)(\\|\\|[^\\}]+?)?\\}\\}");
}
